fix(cf): TTL=1 on proxied records + Global Key via EMAIL+KEY env vars#33
Merged
Conversation
First apply attempt failed with two distinct errors:
Error 1: ttl must be set to 1 when `proxied` is true
on dns.tf line 16, in resource "cloudflare_dns_record" "apex"
Error 2: 400 9106 "Authentication failed"
on cache.tf line 16, in resource "cloudflare_ruleset" "api_cache_rules"
Fix 1 — DNS TTL
CF requires ttl=1 on every record where proxied=true (CF manages TTL
internally; 60 returns 400). The pre-cutover-ramp TTL=60 only applies
to grey-cloud records. Updated:
- dns.tf: apex, www, staging[0] → ttl=1 (kept api at ttl=60, grey-cloud)
- staging.tf: all 5 staging_* records → ttl=1 (all proxied)
- dns.tf header comment updated with the proxied/ttl rule
Fix 2 — CF auth
The Global API Key (cfk_*) is NOT a Bearer-format token. The cloudflare
TF provider only uses Global Key auth (X-Auth-Email + X-Auth-Key
headers) when CLOUDFLARE_EMAIL + CLOUDFLARE_API_KEY env vars are set —
NOT when CLOUDFLARE_API_TOKEN is set (that forces Bearer). Bearer with
a Global Key works for SOME zone endpoints (DNS create) but fails on
Rulesets, R2, and other account-scoped endpoints with 9106.
All 3 TF workflows updated:
- terraform.yml (plan)
- terraform-apply-staging.yml
- terraform-apply-production.yml
Each now passes CLOUDFLARE_EMAIL + CLOUDFLARE_API_KEY to TF instead of
CLOUDFLARE_API_TOKEN. Operator-secrets guard also updated to check the
new env vars (5 secrets total now: EMAIL + API_KEY + R2 AK + R2 SK +
CF_ACCOUNT_ID).
Secrets already set on infra repo via `gh secret set` before this PR
(CLOUDFLARE_EMAIL + CLOUDFLARE_API_KEY are populated).
terraform fmt + validate both clean locally.
After merge: re-trigger terraform-apply-staging.yml. Expected: all 19
staging resources create cleanly. The legacy CLOUDFLARE_API_TOKEN
secret is now unused — can be deleted in a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Terraform plan —
|
Terraform plan —
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #32. First
terraform-apply-staging.ymlrun failed with two distinct errors. This PR fixes both.Fix 1 — DNS TTL on proxied records
CF rejects
ttl=60whenproxied=true(CF manages TTL internally, must be1). Updated all proxied DNS records tottl=1; keptapiatttl=60since it's grey-cloud today (becomes proxied in Phase 4 cut, will need flip then).Fix 2 — Global Key auth via
CLOUDFLARE_EMAIL+CLOUDFLARE_API_KEYGlobal Keys (
cfk_*) are NOT Bearer tokens. The CF TF provider needs them inX-Auth-Email+X-Auth-Keyheaders, only achieved by settingCLOUDFLARE_EMAIL+CLOUDFLARE_API_KEYenv vars (notCLOUDFLARE_API_TOKEN). All 3 TF workflows + the operator-secrets guard updated.The new secrets are already set on the infra repo via
gh secret set(done out-of-band).Test plan
terraform-apply-staging.ymlshould now create all 19 staging resources without 9106 or "ttl must be 1" errorsKnown follow-up
CLOUDFLARE_API_TOKENsecret on infra repo is now unused; can be deleted post-merge.cfat_*token (least-privilege) and revert toCLOUDFLARE_API_TOKENenv. Global Key works but is god-mode.🤖 Generated with Claude Code